package com.jboltai.resource;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.Setting;
import cn.hutool.setting.SettingUtil;
import com.alibaba.fastjson.JSONObject;
import com.jboltai.capability.embedding.JBoltEmbedding;
import com.jboltai.capability.embedding.local.OllamaEmbeddingImpl;
import com.jboltai.capability.embedding.siliconflow.SiliconflowEmbeddingImpl;
import com.jboltai.capability.model.JBoltAI;
import com.jboltai.capability.vdb.types.elasticsearch.ElasticSearchVDBResource;
import com.jboltai.capability.vdb.types.milvus.MilvusVDBResource;
import com.jboltai.capability.vdb.types.postgresql.PostgreSQLVDBResource;
import com.jboltai.capability.vdb.types.tencent.TencentVDBResource;
import com.jboltai.config.AIParamKey;
import com.jboltai.config.JBoltAIConfig;
import com.jboltai.resource.ai.AIModel;
import com.jboltai.resource.ai.AIResource;
import com.jboltai.resource.ai.AIResourceCenter;
import com.jboltai.resource.embedding.EmbeddingModel;
import com.jboltai.resource.embedding.EmbeddingResource;
import com.jboltai.resource.embedding.EmbeddingResourceCenter;
import com.jboltai.resource.functioncall.FunctionResource;
import com.jboltai.resource.functioncall.FunctionResourceCenter;
import com.jboltai.resource.vdb.VDBResource;
import com.jboltai.resource.vdb.VDBResourceCenter;
import com.jboltai.resource.vdb.VDBType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 资源中心
 */
public class ResourceCenter {


    private static final Logger LOGGER = LoggerFactory.getLogger(JBoltAIConfig.LOGGER_NAME);


    /**
     * 注册一个ai模型资源，返回一个资源对象，对象id随机生成
     *
     * @param model
     * @param apiKey
     */
    public static AIResource registerAI(AIModel model, String apiKey) {
        return JBoltAI.registerResource(model, apiKey);
    }


    /**
     * 注册一个ai模型资源，返回一个资源对象，对象id随机生成
     *
     * @param model
     * @param apiKey
     * @param secretKey
     */
    public static AIResource registerAI(AIModel model, String apiKey, String secretKey) {
        return JBoltAI.registerResource(model, "ai-" + IdUtil.fastSimpleUUID(), apiKey, secretKey);
    }


    /**
     * 注册一个ai模型资源，返回一个资源对象，对象id使用指定的id
     *
     * @param id
     * @param model
     * @param apiKey
     * @return
     */
    public static AIResource registerAI(String id, AIModel model, String apiKey) {
        return JBoltAI.registerResource(model, id, apiKey);
    }

    /**
     * 注册一个ai模型资源，返回一个资源对象，对象id使用指定的id
     *
     * @param id
     * @param model
     * @param apiKey
     * @param secretKey
     * @return
     */
    public static AIResource registerAI(String id, AIModel model, String apiKey, String secretKey) {
        return JBoltAI.registerResource(model, id, apiKey, secretKey);
    }

    public static AIResource registerAI(String id, AIModel model, String appId, String apiKey, String secretKey) {
        return JBoltAI.registerResource(model, id, appId, apiKey, secretKey);
    }

    /**
     * 检查某个AI资源是否存在
     *
     * @param model
     * @return
     */
    public static boolean checkAIResourceExist(AIModel model) {
        return AIResourceCenter.checkHasResource(model);
    }

    /**
     * 注册一个符合我们规范的本地大模型
     *
     * @param id
     * @return
     */
    public static AIResource registerLocalAI(String id, String apiUrl) {
        if (StrUtil.isBlank(apiUrl)) {
            throw new IllegalArgumentException("请指定本地大模型的访问地址");
        }
        return JBoltAI.registerResource(AIModel.LOCAL_MODEL, id, null).setApiUrl(apiUrl);
    }

    /**
     * 注册Ollama大模型资源
     *
     * @param id
     * @param apiUrl
     * @param defaultModelName
     * @return
     */
    public static AIResource registerOllamaAI(String id, String apiUrl, String defaultModelName) {
        if (StrUtil.isBlank(apiUrl)) {
            throw new IllegalArgumentException("请指定Ollama的访问地址");
        }
        if (StrUtil.isBlank(defaultModelName)) {
            throw new IllegalArgumentException("请指定Ollama默认使用的大模型");
        }
        AIResource resource = JBoltAI.registerResource(AIModel.OLLAMA, id, null).setApiUrl(apiUrl);
        resource.setDefaultModelName(defaultModelName);
        return resource;

    }

    /**
     * 注册Ollama大模型资源
     *
     * @param apiUrl
     * @param defaultModelName
     * @return
     */
    public static AIResource registerOllamaAI(String apiUrl, String defaultModelName) {
        if (StrUtil.isBlank(apiUrl)) {
            throw new IllegalArgumentException("请指定Ollama的访问地址");
        }
        if (StrUtil.isBlank(defaultModelName)) {
            throw new IllegalArgumentException("请指定Ollama默认使用的大模型");
        }
        AIResource resource = JBoltAI.registerResource(AIModel.OLLAMA, null).setApiUrl(apiUrl);
        resource.setDefaultModelName(defaultModelName);
        return resource;

    }


    /**
     * 从配置文件中注册ai资源
     *
     * @param configFile 配置文件路径
     */
    public static void registerAIFromConfigFile(String configFile) {
        if (StrUtil.isBlank(configFile)) {
            throw new RuntimeException("配置文件路径不能为空");
        }
        if (!configFile.endsWith("setting")) {
            throw new RuntimeException("目前只支持Hutool的setting格式配置文件，文档地址：https://doc.hutool.cn/pages/setting/example");
        }
        registerAIFromSettingConfig(configFile);
    }

    /**
     * 根据Hutool的setting格式配置文件，加载ai资源
     *
     * @param configFile
     */
    private static void registerAIFromSettingConfig(String configFile) {
        Setting allSetting = SettingUtil.get(configFile);
        if (allSetting == null || allSetting.isEmpty()) {
            throw new RuntimeException("AI 配置文件内容不能为空");
        }
        List<String> groups = allSetting.getGroups();
        for (String group : groups) {
            Setting setting = allSetting.getSetting(group);
            Boolean enable = setting.getBool("enable", false);
            if (Objects.equals(enable, false)) {
                continue;
            }
            if (StrUtil.isBlank(group)) {
                throw new RuntimeException(StrUtil.format("AI配置文件中有配置项未设置[分组名]"));
            }
            String type = setting.getStr("type");
            if (StrUtil.isBlank(type)) {
                throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的type为空,无法完成注册", group));
            }
            type = type.toLowerCase();
            AIResource resource = null;
            switch (type) {
                case AIModel.SN_BAICHUAN2:
                case AIModel.SN_BAICHUAN: {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new AIResource(AIModel.BAI_CHUAN, group, apiKey);
                    break;
                }
                case AIModel.SN_CLAUDE: {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new AIResource(AIModel.CLUADE, group, apiKey);
                    break;
                }
                case AIModel.SN_CHATGPT35:
                case AIModel.SN_CHATGPT4: {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new AIResource(AIModel.CHATGPT_4, group, apiKey);
                    break;
                }
                case AIModel.SN_GLM: {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new AIResource(AIModel.GLM, group, apiKey);
                    break;
                }
                case AIModel.SN_MOONSHOT: {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new AIResource(AIModel.MOONSHOT, group, apiKey);
                    break;
                }
                case AIModel.SN_QIANWEN: {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new AIResource(AIModel.QIAN_WEN, group, apiKey);
                    break;
                }
                case AIModel.SN_WENXIN: {
                    String apiKey = setting.getStr("api_key");

                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    String secretKey = setting.getStr("secret_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的secret_key为空,无法完成注册", group));
                    }
                    resource = new AIResource(AIModel.WEN_XIN, group, apiKey, secretKey);
                    break;
                }
                case AIModel.SN_OLLAMA: {
                    String apiUrl = setting.getStr("api_url");
                    if (StrUtil.isBlank(apiUrl)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_url为空,无法完成注册", group));
                    }
                    String model = setting.getStr(AIParamKey.MODEL);
                    if (StrUtil.isBlank(model)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的model为空,无法完成注册", group));
                    }

                    resource = new AIResource(AIModel.OLLAMA, group, null);
                    break;

                }
                case AIModel.SN_LM_STUDIO: {
                    String apiUrl = setting.getStr("api_url");
                    if (StrUtil.isBlank(apiUrl)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_url为空,无法完成注册", group));
                    }
                    String model = setting.getStr(AIParamKey.MODEL);
                    if (StrUtil.isBlank(model)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的model为空,无法完成注册", group));
                    }

                    resource = new AIResource(AIModel.LM_STUDIO, group, null);
                    break;

                }
                case AIModel.SN_SILICONFLOW: {
                    String model = setting.getStr(AIParamKey.MODEL);
                    if (StrUtil.isBlank(model)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的model为空,无法完成注册", group));
                    }
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new AIResource(AIModel.SILICONFLOW, group, apiKey);
                    break;

                }
                case AIModel.SN_VLLM: {
                    String apiUrl = setting.getStr("api_url");
                    if (StrUtil.isBlank(apiUrl)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_url为空,无法完成注册", group));
                    }
                    String model = setting.getStr(AIParamKey.MODEL);
                    if (StrUtil.isBlank(model)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的model为空,无法完成注册", group));
                    }

                    resource = new AIResource(AIModel.vLLM, group, null);
                    break;

                }
                case AIModel.SN_DEEPSEEK: {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new AIResource(AIModel.DEEP_SEEK, group, apiKey);
                    break;
                }
                case AIModel.SN_LOCAL_MODEL: {
                    String apiUrl = setting.getStr("api_url");
                    if (StrUtil.isBlank(apiUrl)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_url为空,无法完成注册", group));
                    }
                    String model = setting.getStr(AIParamKey.MODEL);
                    if (StrUtil.isBlank(model)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的model为空,无法完成注册", group));
                    }

                    resource = new AIResource(AIModel.LOCAL_MODEL, group, null);
                    break;
                }
                case AIModel.SN_XINGHUO: {
                    String apiKey = setting.getStr("api_key");

                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    String secretKey = setting.getStr("secret_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的secret_key为空,无法完成注册", group));
                    }
                    resource = new AIResource(AIModel.XING_HUO, group, apiKey, secretKey);
                    break;
                }


                default:
                    throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的type[{}]不支持,无法完成注册", group, type));

            }
            String model = setting.getStr(AIParamKey.MODEL);
            if (StrUtil.isNotBlank(model)) {
                resource.setDefaultModelName(model);
            }
            String apiUrl = setting.getStr("api_url");
            if (StrUtil.isNotBlank(apiUrl)) {
                resource.setApiUrl(apiUrl);
            }
            String proxyType = setting.getStr("proxy_type");
            if (StrUtil.isNotBlank(proxyType)) {
                proxyType = proxyType.toLowerCase();
                if (!proxyType.equals("http") && !proxyType.equals("sockets")) {
                    throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的proxy_type[{}]不支持,无法完成注册", group, proxyType));
                }
                //要使用代理
                String proxyHost = setting.getStr("proxy_host");
                Integer proxyPort = setting.getInt("proxy_port");
                if (StrUtil.isBlank(proxyHost) || proxyPort == null) {
                    throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的proxy_url或proxy_port为空,无法完成注册", group));
                }
                Proxy proxy = new Proxy(proxyType.equals("http") ? Proxy.Type.HTTP : Proxy.Type.SOCKS, new InetSocketAddress(proxyHost, proxyPort));
                resource.setProxy(proxy);


            }
            String limit = setting.getStr("limit");
            if (StrUtil.isNotBlank(limit)) {
                String[] limits = limit.split(",");
                for (String s : limits) {
                    String[] kv = s.split("/");
                    if (kv.length != 2) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的limit[{}]格式不正确,无法完成注册", group, s));
                    }
                    Integer times = Integer.parseInt(kv[0].trim());
                    String unit = kv[1].trim().toUpperCase();
                    if (unit.equals("MIN") == false && unit.equals("HOUR") == false && unit.equals("DAY") == false) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的limit[{}]的时间单位不支持,无法完成注册", group, s));
                    }
                    TimeUnit timeUnit = null;
                    switch (unit) {
                        case "MIN":
                            timeUnit = TimeUnit.MINUTES;
                            break;
                        case "HOUR":
                            timeUnit = TimeUnit.HOURS;
                            break;
                        case "DAY":
                            timeUnit = TimeUnit.DAYS;
                            break;
                    }
                    resource.setRequestLimit(timeUnit, times);
                }
            }
            AIResourceCenter.register(resource);


        }


    }


    /**
     * 根据id，取消注册ai资源
     *
     * @param id
     */
    public static void unregisterAI(String id) {
        JBoltAI.unregisterResource(id);
    }

    /**
     * 注册一个ai模型资源，返回一个资源对象，对象id随机生成
     *
     * @param model
     * @param apiKey
     */
    public static EmbeddingResource registerEmbedding(EmbeddingModel model, String apiKey) {
        return JBoltEmbedding.registerResource(model, apiKey);
    }

    /**
     * 注册一个ai模型资源，返回一个资源对象，对象id随机生成
     *
     * @param model
     * @param apiKey
     */
    public static EmbeddingResource registerEmbedding(EmbeddingModel model, String apiKey, String secretKey) {
        return JBoltEmbedding.registerResource(model, apiKey, secretKey);
    }


    /**
     * 注册一个ai模型资源，返回一个资源对象，对象id使用指定的id
     *
     * @param id
     * @param model
     * @param apiKey
     * @return
     */
    public static EmbeddingResource registerEmbedding(String id, EmbeddingModel model, String apiKey, String secretKey) {
        return JBoltEmbedding.registerResource(model, id, apiKey, secretKey);
    }

    public static EmbeddingResource registerEmbedding(EmbeddingModel model, String id, String appId, String apiKey, String appSecret) {
        return JBoltEmbedding.registerResource(model, id, appId, apiKey, appSecret);
    }


    public static void registerEmbeddingFromConfigFile(String configFile) {
        if (StrUtil.isBlank(configFile)) {
            throw new RuntimeException("配置文件路径不能为空");
        }
        if (!configFile.endsWith("setting")) {
            throw new RuntimeException("目前只支持Hutool的setting格式配置文件，文档地址：https://doc.hutool.cn/pages/setting/example");
        }
        registerEmbeddingFromSettingConfig(configFile);
    }

    private static void registerEmbeddingFromSettingConfig(String configFile) {
        Setting allSetting = SettingUtil.get(configFile);
        if (allSetting == null || allSetting.isEmpty()) {
            throw new RuntimeException("Embedding 配置文件内容不能为空");
        }
        List<String> groups = allSetting.getGroups();
        for (String group : groups) {
            Setting setting = allSetting.getSetting(group);

            Boolean enable = setting.getBool("enable", false);
            if (Objects.equals(enable, false)) {
                continue;
            }
            if (StrUtil.isBlank(group)) {
                throw new RuntimeException(StrUtil.format("Embedding配置文件中有配置项未设置[分组名]"));
            }
            String type = setting.getStr("type");
            if (StrUtil.isBlank(type)) {
                throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的type为空,无法完成注册", group));
            }
            //type = type.toLowerCase();
            EmbeddingResource resource = null;
            switch (type) {
                case EmbeddingModel.NAME_BAI_CHUAN: {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new EmbeddingResource(EmbeddingModel.BAI_CHUAN, group, apiKey);
                    break;
                }
                case EmbeddingModel.NAME_OPENAI_ADA002: {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new EmbeddingResource(EmbeddingModel.OPENAI_ADA002, group, apiKey);
                    break;
                }
                case EmbeddingModel.NAME_OPENAI_3SMALL: {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new EmbeddingResource(EmbeddingModel.OPENAI_3_SMALL, group, apiKey);
                    break;
                }
                case "tongyi-v3": {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new EmbeddingResource(EmbeddingModel.TONGYI_V3, group, apiKey);
                    break;
                }
                case "tongyi-v2": {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    resource = new EmbeddingResource(EmbeddingModel.TONGYI_V2, group, apiKey);
                    break;
                }
                case EmbeddingModel.NAME_BGE_LARGE_ZH_LOCAL: {
                    String apiUrl = setting.getStr("api_url");
                    if (StrUtil.isBlank(apiUrl)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的api_url未设置,无法完成注册", group));
                    }
                    resource = new EmbeddingResource(EmbeddingModel.LOCAL_BGE_LARGE_ZH);
                    resource.setId(group);
                    resource.setApiUrl(apiUrl);
                    break;
                }
                case EmbeddingModel.NAME_OLLAMA:{
                    String apiUrl = setting.getStr("api_url");
                    if (StrUtil.isBlank(apiUrl)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的api_url未设置,无法完成注册", group));
                    }
                    String modelName = setting.getStr("model");
                    if (StrUtil.isBlank(modelName)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的model未设置,无法完成注册", group));
                    }
                    String dimension = setting.getStr("dimension");
                    if (StrUtil.isBlank(dimension)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的缺少dimension配置,请补充完整", group));
                    }
                    String registerType = EmbeddingModel.NAME_OLLAMA + "-" + modelName;
                    EmbeddingModel model = EmbeddingModel.getCustomModel(registerType);
                    if (model == null) {
                        model = new EmbeddingModel(registerType, modelName, Integer.parseInt(dimension), OllamaEmbeddingImpl.INSTANCE, 9999, 1);
                        EmbeddingModel.registerCustomModel(model);
                    }
                    resource = new EmbeddingResource(model, group, null);
                    break;
                }

                case EmbeddingModel.NAME_SILICONFLOW: {
                    String apiKey = setting.getStr("api_key");
                    if (StrUtil.isBlank(apiKey)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的api_key为空,无法完成注册", group));
                    }
                    String modelName = setting.getStr("model");
                    if (StrUtil.isBlank(modelName)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的model未设置,无法完成注册", group));
                    }
                    String dimension = setting.getStr("dimension");
                    if (StrUtil.isBlank(dimension)) {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的缺少dimension配置,请补充完整", group));
                    }
                    String registerType = EmbeddingModel.NAME_SILICONFLOW + "-" + modelName;
                    EmbeddingModel model = EmbeddingModel.getCustomModel(registerType);
                    if (model == null) {
                        model = new EmbeddingModel(registerType, modelName, Integer.parseInt(dimension), SiliconflowEmbeddingImpl.INSTANCE, 9999, 1);
                        EmbeddingModel.registerCustomModel(model);
                    }
                    resource = new EmbeddingResource(model, group, apiKey);
                    break;
                }


                default:
                    if (type.startsWith("ollama-")) {
                        String apiUrl = setting.getStr("api_url");
                        if (StrUtil.isBlank(apiUrl)) {
                            throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的api_url未设置,无法完成注册", group));
                        }
                        //处理ollama的
                        String modelName = type.substring(7);
                        if (StrUtil.isBlank(modelName)) {
                            throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的type[{}]不支持,请补充模型名称", group, type));
                        }
                        String dimension = setting.getStr("dimension");
                        if (StrUtil.isBlank(dimension)) {
                            throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的缺少dimension配置,请补充完整", group));
                        }
                        if (NumberUtil.isInteger(dimension) == false) {
                            throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的dimension配置不是整数,请修正", group));
                        }
                        EmbeddingModel model = EmbeddingModel.getCustomModel(type);
                        if (model == null) {
                            model = new EmbeddingModel(type, modelName, Integer.parseInt(dimension), OllamaEmbeddingImpl.INSTANCE, 9999, 1);
                            EmbeddingModel.registerCustomModel(model);
                        }
                        resource = new EmbeddingResource(model);
                        resource.setId(group);
                        resource.setApiUrl(apiUrl);
                    } else if (type.startsWith("siliconflow-")) {
                        String apiKey = setting.getStr("api_key");
                        if (StrUtil.isBlank(apiKey)) {
                            throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的api_key为空,无法完成注册", group));
                        }
                        //处理硅基流动的
                        String modelName = type.substring("siliconflow-".length());
                        if (StrUtil.isBlank(modelName)) {
                            throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的type[{}]不支持,请补充模型名称", group, type));
                        }
                        String dimension = setting.getStr("dimension");
                        if (StrUtil.isBlank(dimension)) {
                            throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的缺少dimension配置,请补充完整", group));
                        }
                        if (NumberUtil.isInteger(dimension) == false) {
                            throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的dimension配置不是整数,请修正", group));
                        }
                        EmbeddingModel model = EmbeddingModel.getCustomModel(type);
                        if (model == null) {
                            model = new EmbeddingModel(type, modelName, Integer.parseInt(dimension), SiliconflowEmbeddingImpl.INSTANCE, 9999, 1);
                            EmbeddingModel.registerCustomModel(model);
                        }
                        resource = new EmbeddingResource(model, group, apiKey);
                    } else {
                        throw new RuntimeException(StrUtil.format("Embedding配置文件中[{}]组的type[{}]不支持,无法完成注册", group, type));
                    }

            }
//            String model = setting.getStr(AIParamKey.MODEL);
//            if (StrUtil.isNotBlank(model)) {
//                resource.setDefaultModelName(model);
//            }
            String apiUrl = setting.getStr("api_url");
            if (StrUtil.isNotBlank(apiUrl)) {
                resource.setApiUrl(apiUrl);
            }
            String proxyType = setting.getStr("proxy_type");
            if (StrUtil.isNotBlank(proxyType)) {
                proxyType = proxyType.toLowerCase();
                if (!proxyType.equals("http") && !proxyType.equals("sockets")) {
                    throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的proxy_type[{}]不支持,无法完成注册", group, proxyType));
                }
                //要使用代理
                String proxyHost = setting.getStr("proxy_host");
                Integer proxyPort = setting.getInt("proxy_port");
                if (StrUtil.isBlank(proxyHost) || proxyPort == null) {
                    throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的proxy_url或proxy_port为空,无法完成注册", group));
                }
                Proxy proxy = new Proxy(proxyType.equals("http") ? Proxy.Type.HTTP : Proxy.Type.SOCKS,
                        new InetSocketAddress(proxyHost, proxyPort));
                resource.setProxy(proxy);


            }
            String limit = setting.getStr("limit");
            if (StrUtil.isNotBlank(limit)) {
                String[] limits = limit.split(",");
                for (String s : limits) {
                    String[] kv = s.split("/");
                    if (kv.length != 2) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的limit[{}]格式不正确,无法完成注册", group, s));
                    }
                    Integer times = Integer.parseInt(kv[0].trim());
                    String unit = kv[1].trim().toUpperCase();
                    if (unit.equals("MIN") == false && unit.equals("HOUR") == false && unit.equals("DAY") == false) {
                        throw new RuntimeException(StrUtil.format("AI配置文件中[{}]组的limit[{}]的时间单位不支持,无法完成注册", group, s));
                    }
                    TimeUnit timeUnit = null;
                    switch (unit) {
                        case "MIN":
                            timeUnit = TimeUnit.MINUTES;
                            break;
                        case "HOUR":
                            timeUnit = TimeUnit.HOURS;
                            break;
                        case "DAY":
                            timeUnit = TimeUnit.DAYS;
                            break;
                    }
                    resource.setRequestLimit(timeUnit, times);
                }
            }
            EmbeddingResourceCenter.register(resource);


        }
    }


    /**
     * 注册一个ai模型资源，返回一个资源对象，对象id使用指定的id
     *
     * @param id
     * @param model
     * @param apiKey
     * @return
     */
    public static EmbeddingResource registerEmbedding(String id, EmbeddingModel model, String apiKey) {
        return JBoltEmbedding.registerResource(model, id, apiKey);
    }


    /**
     * 根据id，取消注册ai资源
     *
     * @param id
     */
    public static void unregisterEmbedding(String id) {
        JBoltEmbedding.unregisterResource(id);
    }

    /**
     * 注册Function资源
     *
     * @param functionResource
     * @return
     */
    public static FunctionResource registerFunction(FunctionResource functionResource) {
        return FunctionResourceCenter.register(functionResource);
    }


    /**
     * 注册 function 资源 ,并绑定一个分组id
     *
     * @param groupId          分组id
     * @param functionResource
     * @return
     */
    public static FunctionResource registerFunction(String groupId, FunctionResource functionResource) {
        return FunctionResourceCenter.register(groupId, functionResource);
    }

    /**
     * 注册 function 资源 ,并绑定一个分组id
     *
     * @param groupId           分组id
     * @param functionResources
     */
    public static void registerFunctions(String groupId, FunctionResource... functionResources) {
        FunctionResourceCenter.register(groupId, functionResources);
    }

    /**
     * 取消注册某Function资源
     *
     * @param functionId
     */
    public static void unregisterFunction(String... functionId) {
        FunctionResourceCenter.unregister(functionId);
    }


    /**
     * 从某组将某个Function资源移除
     *
     * @param groupId
     * @param functionId
     */
    public static void removeFunctionFromGroup(String groupId, String functionId) {
        FunctionResourceCenter.removeFromGroup(groupId, functionId);
    }


    public static void unregisterFunctionGroup(String... groupIds) {
        FunctionResourceCenter.unregisterGroup(groupIds);
    }


    /**
     * 注册VDB资源
     *
     * @param id       资源id
     * @param url
     * @param username
     * @param password
     */
    public static VDBResource registerVDB(VDBType type, String id, String url, String username, String password, EmbeddingModel embeddingModel) {
        return registerVDB(type, id, url, username, password, null, embeddingModel, null);
    }

    /**
     * 注册VDB资源
     *
     * @param id       资源id
     * @param url
     * @param username
     * @param password
     */
    public static VDBResource registerVDB(VDBType type, String id, String url, String username, String password, String database, EmbeddingModel embeddingModel) {
        return registerVDB(type, id, url, username, password, database, embeddingModel, null);
    }


    /**
     * 注册VDB资源
     *
     * @param type
     * @param id
     * @param url
     * @param username
     * @param password
     * @param database       绑定的数据库
     * @param embeddingModel 向量化模型
     * @param config         额外的配置
     * @return
     */
    public static VDBResource registerVDB(VDBType type, String id, String url, String username, String password, String database, EmbeddingModel embeddingModel, JSONObject config) {

        if (type == VDBType.TENCENT) {

            return VDBResourceCenter.register(new TencentVDBResource(id, url, username, password, embeddingModel, config).setDatabase(database));

        }

        throw new RuntimeException("不支持的VDB类型[" + type.getSn() + "]");

    }

    /**
     * 注册VDB资源
     *
     * @param resource
     */
    public static VDBResource registerVDB(VDBResource resource) {
        return VDBResourceCenter.register(resource);
    }


    public static void registerVDBFromConfigFile(String configFile) {
        if (StrUtil.isBlank(configFile)) {
            throw new RuntimeException("配置文件路径不能为空");
        }
        if (configFile.endsWith("setting") == false) {
            throw new RuntimeException("目前只支持Hutool的setting格式配置文件，文档地址：https://doc.hutool.cn/pages/setting/example");
        }
        registerVDBFromSettingConfig(configFile);
    }

    private static void registerVDBFromSettingConfig(String configFile) {
        Setting allSetting = SettingUtil.get(configFile);
        if (allSetting == null || allSetting.isEmpty()) {
            throw new RuntimeException("VDB 配置文件内容不能为空");
        }
        List<String> groups = allSetting.getGroups();
        for (String group : groups) {
            Setting setting = allSetting.getSetting(group);
            Boolean enable = setting.getBool("enable", false);
            setting.remove("enable");
            if (Objects.equals(enable, false)) {
                continue;
            }
            if (StrUtil.isBlank(group)) {
                throw new RuntimeException(StrUtil.format("VDB配置文件中有配置项未设置[分组名]"));
            }
            String type = setting.getStr("type");
            setting.remove("type");
            if (StrUtil.isBlank(type)) {
                throw new RuntimeException(StrUtil.format("VDB配置文件中[{}]组的type为空,无法完成注册", group));
            }
            VDBType.InnerType innerType = VDBType.InnerType.get(type.toLowerCase());
            if (innerType == null) {
                throw new RuntimeException(StrUtil.format("VDB配置文件中[{}]组的type[{}]不支持,无法完成注册", group, type));
            }
            String url = setting.getStr("url");
            setting.remove("url");
            String username = setting.getStr("username");
            setting.remove("username");
            String password = setting.getStr("password");
            setting.remove("password");
            String embedding = setting.getStr("embedding");
            setting.remove("embedding");
            Integer defaultShardNum = setting.getInt("default_shard_num");
            setting.remove("defaultShardNum");
            Integer defaultReplicaNum = setting.getInt("default_replica_num");
            setting.remove("defaultReplicaNum");

            if (StrUtil.isBlank(url)) {
                throw new RuntimeException(StrUtil.format("VDB配置文件中[{}]组的url为空,无法完成注册", group));
            }
            if (StrUtil.isBlank(username)) {
                throw new RuntimeException(StrUtil.format("VDB配置文件中[{}]组的username为空,无法完成注册", group));
            }

            if (StrUtil.isBlank(password)) {
                throw new RuntimeException(StrUtil.format("VDB配置文件中[{}]组的password为空,无法完成注册", group));
            }
            if (StrUtil.isBlank(embedding)) {
                throw new RuntimeException(StrUtil.format("VDB配置文件中[{}]组的embedding为空,无法完成注册", group));
            }
            EmbeddingModel embeddingModel = EmbeddingModel.getModel(embedding);
            if (embeddingModel == null) {
                throw new RuntimeException(StrUtil.format("VDB配置文件中[{}]组的embedding[{}]不支持,无法完成注册", group, embedding));
            }

            VDBResource resource = null;
            switch (innerType) {
                case tencent: {

                    resource = new TencentVDBResource(group, url, username, password, embeddingModel);

                    Integer timeout = setting.getInt("timeout");
                    setting.remove("timeout");
                    if (timeout != null) {
                        ((TencentVDBResource) resource).setConnectTimeout(timeout);
                    }
                    break;
                }
                case zilliz:
                case milvus: {
                    if (EmbeddingModel.isTencentInnerModel(embeddingModel)) {
                        throw new RuntimeException(StrUtil.format("VDB配置文件中[{}]组的embedding[{}]是腾讯专用，Milvus无法使用，请更换", group, embedding));
                    }
                    resource = new MilvusVDBResource(group, url, username, password, embeddingModel);
                    break;
                }
                case elasticsearch: {
                    if (EmbeddingModel.isTencentInnerModel(embeddingModel)) {
                        throw new RuntimeException(StrUtil.format("VDB配置文件中[{}]组的embedding[{}]是腾讯专用，elasticSearch无法使用，请更换", group, embedding));
                    }
                    resource = new ElasticSearchVDBResource(group, url, username, password, embeddingModel);
                    break;

                }
                case pgvector: {
                    if (EmbeddingModel.isTencentInnerModel(embeddingModel)) {
                        throw new RuntimeException(StrUtil.format("VDB配置文件中[{}]组的embedding[{}]是腾讯专用，postgresql无法使用，请更换", group, embedding));
                    }
                    resource = new PostgreSQLVDBResource(group, url, username, password, embeddingModel);
                    break;
                }

                default:


            }
            String database = setting.getStr("database");
            if (StrUtil.isBlank(database)) {
                throw new RuntimeException(StrUtil.format("VDB配置文件中[{}]组的database为空,无法完成注册", group));
            }
            resource.setDatabase(database);
            if (defaultShardNum != null) {
                resource.setDefaultShardNum(defaultShardNum);
            }
            if (defaultReplicaNum != null) {
                resource.setDefaultReplicaNum(defaultReplicaNum);
            }

            if (setting.isEmpty() == false) {
                //todo 其他配置
            }


            VDBResourceCenter.register(resource);


        }
    }


    /**
     * 注册腾讯向量数据库
     *
     * @param id
     * @param url
     * @param username
     * @param password
     * @return
     */
    public static VDBResource registerTencentVDB(String id, String url, String username, String password, EmbeddingModel embeddingModel) {
        return VDBResourceCenter.register(new TencentVDBResource(id, url, username, password, embeddingModel));
    }

    /**
     * 注册腾讯向量数据库
     *
     * @param id
     * @param url
     * @param username
     * @param password
     * @param connectTimeout
     * @return
     */
    public static VDBResource registerTencentVDB(String id, String url, String username, String password, EmbeddingModel embeddingModel, int connectTimeout) {
        return VDBResourceCenter.register(new TencentVDBResource(id, url, username, password, embeddingModel, new JSONObject().fluentPut("connectTimeout", connectTimeout)));
    }


    /**
     * 注册Milvus向量数据库
     *
     * @param id
     * @param url
     * @param username
     * @param password
     * @return
     */
    public static VDBResource registerMilvusVDB(String id, String url, String username, String password, EmbeddingModel embeddingModel) {
        return VDBResourceCenter.register(new MilvusVDBResource(id, url, username, password, embeddingModel));
    }
    /**
     * 注册线上版Milvus向量数据库
     *
     * @param id
     * @param url
     * @param username
     * @param password
     * @return
     */
    public static VDBResource registerZillizVDB(String id, String url, String username, String password, EmbeddingModel embeddingModel) {
        return VDBResourceCenter.register(new MilvusVDBResource(id, url, username, password, embeddingModel));
    }

    public static VDBResource registerPostgreSQLVDB(String id, String url, String username, String password, EmbeddingModel embeddingModel) {
        return VDBResourceCenter.register(new PostgreSQLVDBResource(id, url, username, password, embeddingModel));
    }

    public static VDBResource registerElasticSearchVDB(String id, String url, String username, String password, EmbeddingModel embeddingModel) {
        return VDBResourceCenter.register(new ElasticSearchVDBResource(id, url, username, password, embeddingModel));
    }

    /**
     * 取消注册某VDB资源
     *
     * @param id
     */
    public static void unregisterVDB(String id) {
        VDBResourceCenter.unregister(id);
    }

}
